#include "Csv.h"
#include <iostream>
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

namespace quic
{
	Csv::Csv(const std::string &input) : inputCsv(input.c_str())
	{
		if (inputCsv.fail()) {
			string exception("Failed to open ");
			exception += input;
			throw exception;
		}
	}

	Csv::~Csv(void)
	{
		if (inputCsv.is_open()) inputCsv.close();
	}

	vector<string> Csv::nextRecord() {
		vector<string> result;
		string line;
		if(!getline(inputCsv, line)) return result;
		populate(result, line, ',');
		return result;
	}
	
	bool Csv::hasNextRecord() const {return inputCsv.good();}

        void Csv::trim(string& str)
        {
          string::size_type pos = str.find_last_not_of(' ');
          if(pos != string::npos) {
            str.erase(pos + 1);
            pos = str.find_first_not_of(' ');
            if(pos != string::npos) str.erase(0, pos);
          }
          else str.erase(str.begin(), str.end());
        }

	void Csv::populate(vector<string> &record, const string& line, char delimiter)
	{
		int linepos=0;
		int inquotes=false;
		char c;
		int linemax=line.length();
		string curstring;
		record.clear();
	       
		while(line[linepos]!=0 && linepos < linemax)
		{
	       
			c = line[linepos];
	       
			if (!inquotes && curstring.length()==0 && c=='"')
			{
				//beginquotechar
				inquotes=true;
			}
			else if (inquotes && c=='"')
			{
				//quotechar
				if ( (linepos+1 <linemax) && (line[linepos+1]=='"') ) 
				{
					//encountered 2 double quotes in a row (resolves to 1 double quote)
					curstring.push_back(c);
					linepos++;
				}
				else
				{
					//endquotechar
					inquotes=false; 
				}
			}
			else if (!inquotes && c==delimiter)
			{
				//end of field
                                trim(curstring);
				record.push_back( curstring );
				curstring="";
			}
			else if (!inquotes && (c=='\r' || c=='\n') )
			{
                                trim(curstring);
				record.push_back( curstring );
				return;
			}
			else
			{
				curstring.push_back(c);
			}
			linepos++;
		}
                trim(curstring);
		record.push_back( curstring );
		return;
	}
};
